package com.lry.jvm.rtda.heap;

import com.lry.jvm.classfile.MemberInfo;
import com.lry.jvm.classfile.attributes.CodeAttribute;
import lombok.Data;

import java.util.List;

@Data
public class JMethod extends ClassMember{

    private int maxStack;
    private int maxLocals;
    private byte[] code;
    private int argsSlotCount;//方法的参数总共占用多少slot
    
    public static JMethod[] newJMethods(JClass jClass, MemberInfo[] methods) {
        JMethod[] jMethods = new JMethod[methods.length];
        for(int i=0;i<methods.length;i++){
            jMethods[i] = new JMethod();
            newMethod(jMethods[i],jClass,methods[i]);
        }
        return jMethods;
    }


    private static void newMethod(JMethod method,JClass jClass,MemberInfo methodInfo){
        method.setJClass(jClass);
        method.copyMemberInfo(methodInfo);
        method.copyAttributes(methodInfo);
        MethodDescriptorParser methodDescriptorParser = new MethodDescriptorParser();
        MethodDescriptor md = methodDescriptorParser.parseMethodDescriptor(method.getDescriptor());
        method.calcArgsSlotCount(md.getParamTypes());

        if(method.isNative()){
            method.injectCodeAttribute(md.getReturnType());
        }
    }

    //0xfe和0xff是jvm保留的opcode，我们可以用0xfe来实现native调用
    private void injectCodeAttribute(String returnType) {
        this.maxStack = 4;
        this.maxLocals = getArgsSlotCount();
        switch (returnType.charAt(0)){
            //return
            case 'V':
                this.code = new byte[]{(byte) 0xfe, (byte) 0xb1};
                break;
            //dreturn
            case 'D':
                this.code = new byte[]{(byte) 0xfe, (byte) 0xaf};
                break;
            //freturn
            case 'F':
                this.code = new byte[]{(byte) 0xfe, (byte) 0xae};
                break;
            //lreturn
            case 'J':
                this.code = new byte[]{(byte) 0xfe, (byte) 0xad};
                break;
            //areturn
            case 'L':
            case '[':
                this.code = new byte[]{(byte) 0xfe, (byte) 0xb0};
                break;
            //ireturn
            default:
                this.code = new byte[]{(byte) 0xfe, (byte) 0xac};
                break;
        }
    }

    private void calcArgsSlotCount(List<String> paramTypes) {
        for(String paramType:paramTypes){
            argsSlotCount++;
            //long,double占2个slot
            if(paramType.equals("J")||paramType.equals("D")){
                argsSlotCount++;
            }
        }
        //实例方法0号位是this
        if(!isStatic()){
            argsSlotCount++;
        }
    }

    private void copyAttributes(MemberInfo method) {
        CodeAttribute codeAttr = method.codeAttribute();
        if(codeAttr!=null){
            this.maxStack = codeAttr.getMaxStack();
            this.maxLocals = codeAttr.getMaxLocals();
            this.code = codeAttr.getCode();
        }
    }
    
}
